package com.cnswhy.cloud.server.app.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

@Slf4j
public class WxPayData {
	
	
	private  SortedMap<String, Object> m_values = new TreeMap<String, Object>();
	
	public SortedMap<String, Object> GetData(){
		return m_values;
	}
	/**
     * 设置某个字段的值
     * @param key 字段名
      * @param value 字段值
     */
     public void SetValue(String key, Object value)
     {
         m_values.put(key, value);
     }

     /**
     * 根据字段名获取某个字段的值
     * @param key 字段名
      * @return key对应的字段值
     */
     public Object GetValue(String key)
     {
         return m_values.get(key);
     }
     
     /**
      * @将Dictionary转成xml
      * @return 经转换得到的xml串
      * @throws Exception
      **/
      public String ToXml() throws Exception
      {
          //数据为空时不能转化为xml格式
          if (0 == m_values.size())
          {
         	 log.error("WxPayData数据为空!");
              throw new Exception("WxPayData数据为空!");
          }

          String xml = "<xml>";
          Set set = m_values.keySet();
          
          for(Iterator iter = set.iterator(); iter.hasNext();)
          {
 	          String key = (String)iter.next();
 	          Object values = m_values.get(key);
 	          if (values == null)
              {
                  log.error("WxPayData内部含有值为null的字段!======"+key);
                  throw new Exception("WxPayData内部含有值为null的字段!");
              }

              if (values instanceof Integer)
              {
                  xml += "<" + key + ">" + values + "</" + key + ">";
              }
              else if (values instanceof String)
              {
                  xml += "<" + key + ">" + "<![CDATA[" + values + "]]></" + key + ">";
              }
              else//除了String和int类型不能含有其他数据类型
              {
                  log.error("WxPayData字段数据类型错误!");
                  throw new Exception("WxPayData字段数据类型错误!");
              }
          }
  

          xml += "</xml>";
          return xml;
      }
      
      /**
       * @将xml转为Map对象并返回对象内部的数据 不带校验
       * @param xml
       * @return
       * @throws Exception
       */
      public SortedMap<String,Object> FromXmlMap(String xml) throws Exception{
    	  if(StringUtils.isEmpty(xml)){
       		 log.error("将空的xml串转换为WxPayData不合法!");
                throw new Exception("将空的xml串转换为WxPayData不合法!");
            }
       	//这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            InputStream is =  getStringStream(xml);
            Document document = builder.parse(is);

            //获取到document里面的全部结点
            NodeList allNodes = document.getFirstChild().getChildNodes();
            Node node;
            int i=0;
            while (i < allNodes.getLength()) {
                node = allNodes.item(i);
                if(node instanceof Element){
                    m_values.put(node.getNodeName(), node.getTextContent());
                }
                i++;
            }
            return m_values;
      }
      /**
       * @throws Exception 
       * @将xml转为Map对象并返回对象内部的数据 带校验
       * @param
       * @throws
       */
       public SortedMap<String, Object> FromXml(String xml) throws Exception
       {
      	 if(StringUtils.isEmpty(xml)){
      		 log.error("将空的xml串转换为WxPayData不合法!");
               throw new Exception("将空的xml串转换为WxPayData不合法!");
           }
      	//这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
           DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
           DocumentBuilder builder = factory.newDocumentBuilder();
           InputStream is =  getStringStream(xml);
           Document document = builder.parse(is);

           //获取到document里面的全部结点
           NodeList allNodes = document.getFirstChild().getChildNodes();
           Node node;
           int i=0;
           while (i < allNodes.getLength()) {
               node = allNodes.item(i);
               if(node instanceof Element){
                   m_values.put(node.getNodeName(), node.getTextContent());
               }
               i++;
           }
           try
           {
  			//2015-06-29 错误是没有签名
  			if(m_values.get("return_code").toString() != "SUCCESS")
  			{
  				return m_values;
  			}
            CheckSign();//验证签名,不通过会抛异常
           }
           catch(Exception ex)
           {
               throw new Exception(ex.getMessage());
           }
           
           return m_values;
       }
       
       public static InputStream getStringStream(String sInputString) throws UnsupportedEncodingException {
           ByteArrayInputStream tInputStringStream = null;
           if (sInputString != null && !sInputString.trim().equals("")) {
               tInputStringStream = new ByteArrayInputStream(sInputString.getBytes("UTF-8"));
           }
           return tInputStringStream;
       }
       
       /**
        * 
        * 检测签名是否正确
        * 正确返回true，错误抛异常
       * @throws Exception 
        */
        public boolean CheckSign() throws Exception
        {
            //如果设置了签名但是签名为空，则抛异常
            if(m_values.get("sign") == null || m_values.get("sign").toString() == "")
            {
                log.error("WxPayData签名存在但不合法!");
                throw new Exception("WxPayData签名存在但不合法!");
            }

            //获取接收到的签名
            String return_sign = m_values.get("sign").toString();

            //在本地计算新的签名
            String cal_sign = WxSignUtils.getSign(m_values);

            if (cal_sign == return_sign)
            {
                return true;
            }

            log.error("WxPayData签名验证错误!");
            throw new Exception("WxPayData签名验证错误!");
        }
        
}
